[PCI] back: New virtual pci backend: slot
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Tue, 8 Aug 2006 09:17:42 +0000 (10:17 +0100)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Tue, 8 Aug 2006 09:17:42 +0000 (10:17 +0100)
This backend use a slot per pci device.  Contrary to vpci two functions from
one slot appear as two slots. This is useful on ia64 because it doesn't scan
functions > 0 if function 0 does not exist.

Signed-off-by: Tristan Gingold <tristan.gingold@bull.net>
buildconfigs/linux-defconfig_xen0_ia64
buildconfigs/linux-defconfig_xen0_x86_32
buildconfigs/linux-defconfig_xen0_x86_64
buildconfigs/linux-defconfig_xen_ia64
buildconfigs/linux-defconfig_xen_x86_32
buildconfigs/linux-defconfig_xen_x86_64
linux-2.6-xen-sparse/drivers/xen/Kconfig
linux-2.6-xen-sparse/drivers/xen/pciback/Makefile
linux-2.6-xen-sparse/drivers/xen/pciback/slot.c [new file with mode: 0644]

index cd2008f9daecc5694b30baa16fa22fe15fa01875..51379834a6179e94e531913a284778813f16f1b8 100644 (file)
@@ -1533,8 +1533,9 @@ CONFIG_XEN_BLKDEV_BACKEND=y
 # CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
 CONFIG_XEN_NETDEV_LOOPBACK=y
 CONFIG_XEN_PCIDEV_BACKEND=y
-CONFIG_XEN_PCIDEV_BACKEND_VPCI=y
+# CONFIG_XEN_PCIDEV_BACKEND_VPCI is not set
 # CONFIG_XEN_PCIDEV_BACKEND_PASS is not set
+CONFIG_XEN_PCIDEV_BACKEND_SLOT=y
 # CONFIG_XEN_PCIDEV_BE_DEBUG is not set
 # CONFIG_XEN_TPMDEV_BACKEND is not set
 CONFIG_XEN_BLKDEV_FRONTEND=y
index 3280f54f2cdca4e135bbaa3e5a0191466121e8e7..8cd6a5e503bd2d52f12bf2a482738c98ae651ff9 100644 (file)
@@ -1320,6 +1320,7 @@ CONFIG_XEN_BACKEND=y
 CONFIG_XEN_PCIDEV_BACKEND=y
 # CONFIG_XEN_PCIDEV_BACKEND_VPCI is not set
 CONFIG_XEN_PCIDEV_BACKEND_PASS=y
+# CONFIG_XEN_PCIDEV_BACKEND_SLOT is not set
 # CONFIG_XEN_PCIDEV_BE_DEBUG is not set
 CONFIG_XEN_BLKDEV_BACKEND=y
 CONFIG_XEN_BLKDEV_TAP=y
index c219cd7f3c9c6d6b5b2fbd0c3369f4c6df57ac2c..05c6fed107c31ec704f6610a4d3f25732c923dae 100644 (file)
@@ -1261,6 +1261,7 @@ CONFIG_XEN_BACKEND=y
 CONFIG_XEN_PCIDEV_BACKEND=y
 # CONFIG_XEN_PCIDEV_BACKEND_VPCI is not set
 CONFIG_XEN_PCIDEV_BACKEND_PASS=y
+# CONFIG_XEN_PCIDEV_BACKEND_SLOT is not set
 # CONFIG_XEN_PCIDEV_BE_DEBUG is not set
 CONFIG_XEN_BLKDEV_BACKEND=y
 CONFIG_XEN_BLKDEV_TAP=y
index 8ce5402772cf234884b84b0cec598039e2408cf8..a5eca9a8ad17a89c8dcd2aaa80a34724ffa4a061 100644 (file)
@@ -1539,8 +1539,9 @@ CONFIG_XEN_BLKDEV_BACKEND=y
 # CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
 CONFIG_XEN_NETDEV_LOOPBACK=y
 CONFIG_XEN_PCIDEV_BACKEND=y
-CONFIG_XEN_PCIDEV_BACKEND_VPCI=y
+# CONFIG_XEN_PCIDEV_BACKEND_VPCI is not set
 # CONFIG_XEN_PCIDEV_BACKEND_PASS is not set
+CONFIG_XEN_PCIDEV_BACKEND_SLOT=y
 # CONFIG_XEN_PCIDEV_BE_DEBUG is not set
 # CONFIG_XEN_TPMDEV_BACKEND is not set
 CONFIG_XEN_BLKDEV_FRONTEND=y
index 286e47d71e27dace9f793abff77f8dea2cb400a9..5c7e66550bac75a0f50cf1146a4c8a1892fe473c 100644 (file)
@@ -3021,6 +3021,7 @@ CONFIG_XEN_BACKEND=y
 CONFIG_XEN_PCIDEV_BACKEND=m
 CONFIG_XEN_PCIDEV_BACKEND_VPCI=y
 # CONFIG_XEN_PCIDEV_BACKEND_PASS is not set
+# CONFIG_XEN_PCIDEV_BACKEND_SLOT is not set
 # CONFIG_XEN_PCIDEV_BE_DEBUG is not set
 CONFIG_XEN_BLKDEV_BACKEND=y
 CONFIG_XEN_BLKDEV_TAP=y
index 6299af3b5ee68113eade66fb60d80cb930e3d41b..019531708b74b74e4fc0ee78659d8c1ebbfec6fa 100644 (file)
@@ -2853,6 +2853,7 @@ CONFIG_XEN_BACKEND=y
 CONFIG_XEN_PCIDEV_BACKEND=m
 # CONFIG_XEN_PCIDEV_BACKEND_VPCI is not set
 CONFIG_XEN_PCIDEV_BACKEND_PASS=y
+# CONFIG_XEN_PCIDEV_BACKEND_SLOT is not set
 # CONFIG_XEN_PCIDEV_BE_DEBUG is not set
 CONFIG_XEN_BLKDEV_BACKEND=y
 CONFIG_XEN_BLKDEV_TAP=y
index b8a94799274894b59b4f188321e78decf57624f9..da25eeeaa2c5bc13782343225ed17f4b9e7907ba 100644 (file)
@@ -117,7 +117,7 @@ config XEN_PCIDEV_BACKEND_VPCI
          This PCI Backend hides the true PCI topology and makes the frontend
          think there is a single PCI bus with only the exported devices on it.
          For example, a device at 03:05.0 will be re-assigned to 00:00.0. A
-         second device at 02:1a.0 will be re-assigned to 00:01.0.
+         second device at 02:1a.1 will be re-assigned to 00:01.1.
 
 config XEN_PCIDEV_BACKEND_PASS
        bool "Passthrough"
@@ -129,6 +129,15 @@ config XEN_PCIDEV_BACKEND_PASS
          which depend on finding their hardward in certain bus/slot
          locations.
 
+config XEN_PCIDEV_BACKEND_SLOT
+       bool "Slot"
+       ---help---
+         This PCI Backend hides the true PCI topology and makes the frontend
+         think there is a single PCI bus with only the exported devices on it.
+         Contrary to the virtual PCI backend, a function becomes a new slot.
+         For example, a device at 03:05.2 will be re-assigned to 00:00.0. A
+         second device at 02:1a.1 will be re-assigned to 00:01.0.
+
 endchoice
 
 config XEN_PCIDEV_BE_DEBUG
index b1d009d4ef0090924d8ba3b7b74a1be4aa6b06a3..c7185fb7c87713848ae8c709947f4d023c0ef4fd 100644 (file)
@@ -7,6 +7,7 @@ pciback-y += conf_space.o conf_space_header.o \
             conf_space_capability_pm.o \
              conf_space_quirks.o
 pciback-$(CONFIG_XEN_PCIDEV_BACKEND_VPCI) += vpci.o
+pciback-$(CONFIG_XEN_PCIDEV_BACKEND_SLOT) += slot.o
 pciback-$(CONFIG_XEN_PCIDEV_BACKEND_PASS) += passthrough.o
 
 ifeq ($(CONFIG_XEN_PCIDEV_BE_DEBUG),y)
diff --git a/linux-2.6-xen-sparse/drivers/xen/pciback/slot.c b/linux-2.6-xen-sparse/drivers/xen/pciback/slot.c
new file mode 100644 (file)
index 0000000..09293fc
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * PCI Backend - Provides a Virtual PCI bus (with real devices)
+ *               to the frontend
+ *
+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil> (vpci.c)
+ *   Author: Tristan Gingold <tristan.gingold@bull.net>, from vpci.c
+ */
+
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include "pciback.h"
+
+/* There are at most 32 slots in a pci bus.  */
+#define PCI_SLOT_MAX 32
+
+#define PCI_BUS_NBR 2
+
+struct slot_dev_data {
+       /* Access to dev_list must be protected by lock */
+       struct pci_dev *slots[PCI_BUS_NBR][PCI_SLOT_MAX];
+       spinlock_t lock;
+};
+
+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
+                                   unsigned int domain, unsigned int bus,
+                                   unsigned int devfn)
+{
+       struct pci_dev *dev = NULL;
+       struct slot_dev_data *slot_dev = pdev->pci_dev_data;
+       unsigned long flags;
+
+       if (domain != 0 || PCI_FUNC(devfn) != 0)
+               return NULL;
+
+       if (PCI_SLOT(devfn) >= PCI_SLOT_MAX || bus >= PCI_BUS_NBR)
+               return NULL;
+
+       spin_lock_irqsave(&slot_dev->lock, flags);
+       dev = slot_dev->slots[bus][PCI_SLOT(devfn)];
+       spin_unlock_irqrestore(&slot_dev->lock, flags);
+
+       return dev;
+}
+
+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
+{
+       int err = 0, slot, bus;
+       struct slot_dev_data *slot_dev = pdev->pci_dev_data;
+       unsigned long flags;
+
+       if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) {
+               err = -EFAULT;
+               xenbus_dev_fatal(pdev->xdev, err,
+                                "Can't export bridges on the virtual PCI bus");
+               goto out;
+       }
+
+       spin_lock_irqsave(&slot_dev->lock, flags);
+
+       /* Assign to a new slot on the virtual PCI bus */
+       for (bus = 0; bus < PCI_BUS_NBR; bus++)
+               for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+                       if (slot_dev->slots[bus][slot] == NULL) {
+                               printk(KERN_INFO
+                                      "pciback: slot: %s: assign to virtual slot %d, bus %d\n",
+                                      pci_name(dev), slot, bus);
+                               slot_dev->slots[bus][slot] = dev;
+                               goto unlock;
+                       }
+               }
+
+       err = -ENOMEM;
+       xenbus_dev_fatal(pdev->xdev, err,
+                        "No more space on root virtual PCI bus");
+
+      unlock:
+       spin_unlock_irqrestore(&slot_dev->lock, flags);
+      out:
+       return err;
+}
+
+void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
+{
+       int slot, bus;
+       struct slot_dev_data *slot_dev = pdev->pci_dev_data;
+       struct pci_dev *found_dev = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&slot_dev->lock, flags);
+
+       for (bus = 0; bus < PCI_BUS_NBR; bus++)
+               for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+                       if (slot_dev->slots[bus][slot] == dev) {
+                               slot_dev->slots[bus][slot] = NULL;
+                               found_dev = dev;
+                               goto out;
+                       }
+               }
+
+      out:
+       spin_unlock_irqrestore(&slot_dev->lock, flags);
+
+       if (found_dev)
+               pcistub_put_pci_dev(found_dev);
+}
+
+int pciback_init_devices(struct pciback_device *pdev)
+{
+       int slot, bus;
+       struct slot_dev_data *slot_dev;
+
+       slot_dev = kmalloc(sizeof(*slot_dev), GFP_KERNEL);
+       if (!slot_dev)
+               return -ENOMEM;
+
+       spin_lock_init(&slot_dev->lock);
+
+       for (bus = 0; bus < PCI_BUS_NBR; bus++)
+               for (slot = 0; slot < PCI_SLOT_MAX; slot++)
+                       slot_dev->slots[bus][slot] = NULL;
+
+       pdev->pci_dev_data = slot_dev;
+
+       return 0;
+}
+
+int pciback_publish_pci_roots(struct pciback_device *pdev,
+                             publish_pci_root_cb publish_cb)
+{
+       /* The Virtual PCI bus has only one root */
+       return publish_cb(pdev, 0, 0);
+}
+
+void pciback_release_devices(struct pciback_device *pdev)
+{
+       int slot, bus;
+       struct slot_dev_data *slot_dev = pdev->pci_dev_data;
+       struct pci_dev *dev;
+
+       for (bus = 0; bus < PCI_BUS_NBR; bus++)
+               for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+                       dev = slot_dev->slots[bus][slot];
+                       if (dev != NULL)
+                               pcistub_put_pci_dev(dev);
+               }
+
+       kfree(slot_dev);
+       pdev->pci_dev_data = NULL;
+}